//
//  RSI.cpp
//  Chart
//
//  Created by CaoJun on 13-7-15.
//
//

#include "RSI.h"

using namespace ytx;
using namespace std;

RSI::RSI(IndexConfig indexConfig):IndexData(indexConfig, 2)
{
    type = QuotationType::RSI;
    indexName = "RSI";
    lineData.assign(2, vector<double>());
    this->setColumn(Rect(2,5,5));
}

RSI::~RSI()
{

}

void RSI::updateLastest(Quotation * data)
{
    int n = para.value[0];
    int m = para.value[1];
    
    n = (int) Tools::between(para.range[0].first, para.range[0].second, n);
    m = (int) Tools::between(para.range[1].first, para.range[1].second, m);
    
    vector<int> toMax;
    toMax.push_back(n);
    toMax.push_back(m);
    
    int maxPara = (*(max_element(toMax.begin(), toMax.end(), Tools::compareForMax)));
    int len = data->getDataLength();
    if (len < maxPara){
        return;
    }
    int i = len - 1;
    double c = data->kLineData[i].close,
    pc = data->kLineData[i - 1].close,
    up = fmax(c-pc, 0),
    down = fmax(pc-c, 0);
    
    double upAvgN = (penultimateUPAVGN * (n - 1) + up) / n, downAvgN = (penultimateDNAVGN * (n - 1) + down) / n;
    
    double upAvgM = (penultimateUPAVGM * (m - 1) + up) / m, downAvgM = (penultimateDNAVGM * (m - 1) + down) / m;
    
    double RSI1 = upAvgN * 100 / (upAvgN + downAvgN), RSI2 = upAvgM * 100 / (upAvgM + downAvgM);

    lineData[0].back() = RSI1;
    lineData[1].back() = RSI2;
}

void RSI::calculate(Quotation * data)
{
    lineData.clear();
    
    int n = para.value[0];
    int m = para.value[1];
    
    n = (int) Tools::between(para.range[0].first, para.range[0].second, n);
    m = (int) Tools::between(para.range[1].first, para.range[1].second, m);
    
    vector<int> toMax;
    toMax.push_back(n);
    toMax.push_back(m);
    
    int maxPara = (*(max_element(toMax.begin(), toMax.end(), Tools::compareForMax)));
    
    if (data->getDataLength() < maxPara){
        return;
    }
    
    int i = 1;
    int j = data->getDataLength();
    
    vector<double> up;
    up.push_back(numeric_limits<double>::quiet_NaN());
    vector<double> down;
    down.push_back(numeric_limits<double>::quiet_NaN());
    vector<double> upAvgN(n);
    vector<double> downAvgN(n);
    vector<double> upAvgM(m);
    vector<double> downAvgM(m);
    vector<double> RSI1;
    vector<double> RSI2;
    double c , pc;
    
    while (i < j) {
        c = data->kLineData[i].close;
        pc = data->kLineData[i - 1].close;
        up.push_back(fmax(c-pc, 0));
        down.push_back(fmax(pc-c, 0));
        i++;
    }
    
    upAvgN = validation(n, upAvgN);
    downAvgN = validation(n, downAvgN);
    
    upAvgN.push_back(computeSum(up, 1, n+1, n));
    downAvgN.push_back(computeSum(down, 1, n+1, n));
    
    upAvgM = validation(m, upAvgM);
    downAvgM = validation(m, downAvgM);
    
    upAvgM.push_back(computeSum(up, 1, m+1, m));
    downAvgM.push_back(computeSum(down, 1, m+1, m));
    
    i = 0;
    while (i < j) {
        if (i >= n + 1) {
            upAvgN.push_back((upAvgN[i - 1] * (n - 1) + up[i]) / n);
            downAvgN.push_back((downAvgN[i - 1] * (n - 1) + down[i]) / n);
        }
        
        if (i >= n) RSI1.push_back(upAvgN[i] * 100 / (upAvgN[i] + downAvgN[i]));
        else RSI1.push_back(numeric_limits<double>::quiet_NaN());
        
        if (i >= m + 1) {
            upAvgM.push_back((upAvgM[i - 1] * (m - 1) + up[i]) / m);
            downAvgM.push_back((downAvgM[i - 1] * (m - 1) + down[i]) / m);
        }
        if (i >= m) RSI2.push_back(upAvgM[i] * 100 / (upAvgM[i] + downAvgM[i]));
        else RSI2.push_back(numeric_limits<double>::quiet_NaN());
        i++;
    }
    int penultimate = (int)upAvgN.size()-2;
    penultimateUPAVGN = upAvgN[penultimate];
    penultimateDNAVGN = downAvgN[penultimate];
    penultimateUPAVGM = upAvgM[penultimate];
    penultimateDNAVGM = downAvgM[penultimate];
    
    lineData.push_back(RSI1);
    lineData.push_back(RSI2);
}

string RSI::getCrosshairYData(int index)
{
    return Tools::Convert2FixString(lineData[0][index], toFix);
}

int RSI::getDataLength() const
{
    return hasData() ? (int)lineData[0].size() :0;
}

bool RSI::hasData() const
{
    return (lineData.size() > 0 && lineData[0].size() > 0);
}

bool RSI::hasData(int index) const
{

    if (hasData())
    {
        int count = (int)lineData[0].size();
        return 0 <= index && index < count;
    }
    else{
        return false;
    }
}

std::pair<double, double> RSI::getAdjustedDataMinMax(const Rectangle & rect) const
{
    return make_pair(0, 100);
}

std::vector<std::pair<std::string, std::string> > RSI::getTopSideText(int index) const
{
    return Quotation::getTopSideText(lineData, index);
}

std::vector<std::pair<double, std::string> > RSI::getLeftSideText(int startIndex, int endIndex, const Rectangle & rect, const Style & style) const
{
    string stcolor = style.sideTextColor;
    vector<pair<double, string> > result;
    if (rect.getColumn() > 2) {
        result.push_back(make_pair(0, stcolor));
        result.push_back(make_pair(20, stcolor));
        result.push_back(make_pair(40, stcolor));
        result.push_back(make_pair(60, stcolor));
        result.push_back(make_pair(80, stcolor));
        result.push_back(make_pair(100, stcolor));
    }else{
        result.push_back(make_pair(0, stcolor));
        result.push_back(make_pair(50, stcolor));
        result.push_back(make_pair(100, stcolor));
    }
    return result;
}
